#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef WIN32
#include "windows.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include "pthread.h"

#include "BList.h"
#include "BVector.h"
#include "geometrics.h"
#include "quaternion.h"
#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"

#include "AWEntity.h"
#include "AWMessage.h"
#include "AWBrain.h"
#include "AWTracerBrain.h"
#include "AWThreadedBrain.h"
#include "AWNOOSBrain.h"
#include "AWNOOSLearnerBrain.h"

#include "CaseBaseUtils.h"

#include "psm.h"

#include "loader.h"



FeatureTerm *AW_NOOSLearnerBrain::solve_problem_JBartering(FeatureTerm *problem,Sort *sort,Symbol *my_name,bool test)
{
	int i;
	char *str;
	AW_Message *m;
	Symbol *agent_name;
	List<Symbol> agent_names;
	FeatureTerm *prediction,*f,*op,*individual_JERs;
	List<FeatureTerm> individual_solutions;

	/* Retrieve the set of other agents: */ 
	pthread_mutex_lock(&m_sensor_data_mutex);
	m_sensor_data.Rewind();
	while(m_sensor_data.Iterate(f)) {						
		if (f->getSort()->is_a(m_ontology->get_sort("sensed-agent")) &&
			!f->getSort()->is_a(m_ontology->get_sort("sensed-self"))) {
			Symbol *name=f->featureValueQuick("name")->getSymbol();
			if (name->get()[0]=='L' &&
				name->get()[1]=='e' &&
				name->get()[2]=='a' &&
				name->get()[3]=='r' &&
				name->get()[4]=='n' &&
				name->get()[5]=='e' &&
				name->get()[6]=='r') {
				agent_names.Add(new Symbol(name));
			} /* if */ 
		} /* if */ 	
	} /* while */ 
	pthread_mutex_unlock(&m_sensor_data_mutex);

	/* Do not use all the agents: */ 
/*
	{
		delete agent_names.ExtractIni();
		delete agent_names.ExtractIni();
		delete agent_names.ExtractIni();
//		delete agent_names.ExtractIni();
	}
*/

	/* Send the problem to the other agents: */ 
	agent_names.Rewind();
	while(agent_names.Iterate(agent_name)) {
		/* Send the problem: */ 
		f=new FeatureTerm((char *)0,m_ontology->get_sort("request-individual-predict-message"),1,
						  "problem",new FeatureTerm(problem));

		str=f->toStringNOOS(m_memory);
		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
						   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
		delete []str;
		delete f;
		enqueue_operator(op);
	} /* while */ 

	/* Solve the problem individually: */ 
	individual_JERs=build_jers(problem,sort,my_name);
	individual_solutions.Add(individual_JERs);

	/* Receive the solution from the others: */ 
	for(i=0;i<agent_names.Length();i++) {
		/* Wait for the confirmation of the agent: */ 
		wait_message();
		m=get_message();
		prediction=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
		individual_solutions.Add(prediction);
		delete m;
	} /* for */ 

	/* Construct the list of JERs: */ 
	write_debug_report("[%s]: With %i agents.\n",my_name->get(),individual_solutions.Length());
	individual_solutions.Rewind();
	while(individual_solutions.Iterate(prediction)) {
		if (prediction->isFeatureTerm()) {
			JBartering_collected_JERs.Add(new FeatureTerm(prediction));
		} else {
			List<FeatureTerm> *l;
			l=prediction->set_values_quick();
			l->Rewind();
			while(l->Iterate(prediction)) {
				JBartering_collected_JERs.Add(new FeatureTerm(prediction));
			} /* while */ 
		} /* if */ 
	} /* while */ 
	write_debug_report("[%s]: %i JERs collected.\n",my_name->get(),JBartering_collected_JERs.Length());

	/* Answer the individual solution: */ 
	{
		List<FeatureTerm> individual_solutions;

		individual_solutions.Add(new FeatureTerm(individual_JERs));
		return BWAV(&individual_solutions);
	}
} /* AW_NOOSLearnerBrain::solve_problem_JBartering */ 





void AW_NOOSLearnerBrain::JBartering(FeatureTerm *problem_solution,Sort *sort,Symbol *my_name,bool test)
{
	Symbol *agent_name;
	FeatureTerm *JER;

	/* Construct the refutation sets: */ 
	{
		int pos=-1;
		List< List<FeatureTerm> > *l;
		List<FeatureTerm> *refutationset;
		FeatureTerm *justification;
		FeatureTerm *solution;

		JBartering_collected_JERs.Rewind();
		while(JBartering_collected_JERs.Iterate(JER)) {
			agent_name=JER->featureValueQuick("agent")->getSymbol();
			if (!agent_name->cmp(my_name)) {
				justification=JER->featureValueQuick("justification");
				solution=JER->featureValueQuick("solution");

				// Only consider those JERs that are wrong:
				if (!solution->equivalents(problem_solution)) {
	
					pos=JBartering_refutationsets_agent_name.Position(agent_name);
					if (pos==-1) {
						JBartering_refutationsets_agent_name.Add(new Symbol(agent_name));
						JBartering_refutationsets.Add(new List< List<FeatureTerm> >);
					} /* if */ 

					l=JBartering_refutationsets[pos];

					refutationset=new List<FeatureTerm>;
					{
						List<FeatureTerm> *cases=m_casebase->SearchFT(sort);
						FeatureTerm *c,*d,*s;

						cases->Rewind();
						while(cases->Iterate(c)) {
							d=get_description(c);
							s=get_solution(c);
							if (justification->subsumes(d) &&
								!s->equivalents(solution)) {
								refutationset->Add(new FeatureTerm(c));
							} /* if */ 
							delete s;
							delete d;
						} /* while */ 

						cases->ExtractAll();
						delete cases;
					}

					if (refutationset->EmptyP()) {
						delete refutationset;
					} else {
						l->Add(refutationset);
					} /* if */	

				} /* if */ 
			} /* if */ 

		} /* while */ 

		JBartering_collected_JERs.Delete();
	}

	/* If I've any refutation sets for any agent, send bartering offers: */ 
	{
		List< List<FeatureTerm> > *l;
		List<FeatureTerm> *l2;
		FeatureTerm *c;

		JBartering_refutationsets_agent_name.Rewind();
		JBartering_refutationsets.Rewind();
		while(JBartering_refutationsets_agent_name.Iterate(agent_name) &&
			  JBartering_refutationsets.Iterate(l)) {
			write_debug_report("[%s]:Refutation sets for agent %s:\n",my_name->get(),agent_name->get());

			// Print the refutation sets:
			l->Rewind();
			while(l->Iterate(l2)) {
				l2->Rewind();
				write_debug_report("[%s]:",my_name->get());
				while(l2->Iterate(c)) {
					write_debug_report("%s ",c->getName()->get());
				} /* while */ 
				write_debug_report("\n");
			} /* while */ 

			// Compute the best offer:
			if (l->Length()>0) {
				List<FeatureTerm> *offer;

				offer=JBartering_cases_to_offer(l,l->Length());

				write_debug_report("[%s] Offer: ",my_name->get());
				offer->Rewind();
				while(offer->Iterate(c)) {
					write_debug_report("%s ",c->getName()->get());
				} /* while */ 
				write_debug_report("\n");

				// Make offer:
				{
					FeatureTerm *f=FeatureTerm::SetFeatureTerm((Symbol *)0);
					FeatureTerm *msg,*op;
					char *str;
					int i;
					for(i=0;i<offer->Length();i++) f->addSetValue(new FeatureTerm(offer->operator [](i)));

					msg=new FeatureTerm((char *)0,m_ontology->get_sort("jbartering-cases"),1,
										"cases",f);

					str=msg->toStringNOOS(m_memory);
					op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
									   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
									   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
					delete []str;
					delete msg;
					enqueue_operator(op);
					write_debug_report("[%s] offer sent to %s\n",my_name->get(),agent_name->get());
				}

				// Wait for answer:
				{
					FeatureTerm *m_content;
					AW_Message *m;
					List<FeatureTerm> *cases1;
					int n1,n2,n3;

					wait_message();
					m=get_message();
					m_content=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);

					cases1=m_content->featureValueQuick("cases")->set_values_quick();
					n1=cases1->Length();
					n2=offer->Length();

					n3=(n1<n2 ? n1:n2);

					write_debug_report("[%s] Received Offer: ",my_name->get());
					cases1->Rewind();
					while(cases1->Iterate(c)) {
						write_debug_report("%s ",c->getName()->get());
					} /* while */ 
					write_debug_report("\n");
					write_debug_report("[%s] %i cases exchanged.\n",my_name->get(),n3);

					// Retain the first 'n3' cases of 'cases1':
					{
						int i;
						for(i=0;i<n3;i++) retain_case(new FeatureTerm(cases1->operator [](i)));
					}


					// Remove the first 'n3' cases from the list of cases to send:
					{
						int i;
						List< List<FeatureTerm> > to_delete;
						List<FeatureTerm> *l_tmp;
						FeatureTerm *c;

						for(i=0;i<n3;i++) {
							c=offer->operator [](i);
							l->Rewind();
							while(l->Iterate(l2)) {
								int pos;
								pos=l2->Position(c);
								if (pos!=-1) l2->DeletePosition(pos);

								if (l2->EmptyP() && !to_delete.MemberRefP(l2)) to_delete.Add(l2);
							} /* while */ 
						} /* for */ 

						while(!to_delete.EmptyP()) {
							l_tmp=to_delete.ExtractIni();
							l->DeleteElement(l_tmp);
							delete l_tmp;
						} /* while */ 
					}

					delete m_content;
					delete m;
				}

				delete offer;
			} /* if */ 
		} /* while */ 
	}
} /* AW_NOOSLearnerBrain::JBartering */ 




List<FeatureTerm> *AW_NOOSLearnerBrain::JBartering_cases_to_offer(List< List<FeatureTerm> > *refutation_sets,int size)
{
	List<FeatureTerm> *offer=new List<FeatureTerm>;
	List<FeatureTerm> *l;
	int i=0,len=refutation_sets->Length();

	if (size==-1) size=len;

	for(i=0;i<len && offer->Length()<size;i++) {
		l=refutation_sets->operator [](i);
		
		{
			FeatureTerm *best_case=0,*c=0;
			int best_future_appearances=0,fa=0;
			int j;

			l->Rewind();
			while(l->Iterate(c)) {
				if (!offer->MemberP(c)) {
					fa=0;
					for(j=i+1;j<len;j++) if (refutation_sets->operator [](j)->MemberP(c)) fa++;

					if (best_case==0 || fa<best_future_appearances) {
						best_case=c;
						best_future_appearances=fa;
					} /* if */ 
				} /* while */ 
			} /* while */ 

			if (best_case!=0) offer->Add(new FeatureTerm(best_case));
		}
	} /* for */ 

	return offer;
} /* AW_NOOSLearnerBrain::JBartering_cases_to_offer */ 


